﻿// 2022/4/1: 首个版本
// 2023/2/15: 远程采集模式时禁用
// 2023/4/10: 增加Load/Save方法
// 2024/1/29: GetConfigStatus输出errorHint
// 2024/6/19: 继承ModuleConfig，支持异步
// 2024/11/21: 修正SetConfig

using System;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
using ASEva;
using ASEva.Utility;

namespace CommonSource
{
    class AudioConfig : ModuleConfig
    {
        public AudioConfig()
        {
            RecordDriverID = null;
            RecordDeviceID = null;
            ReplayDriverID = null;
            ReplayDeviceID = null;
        }

        public static async Task<AudioConfig> Load(object caller)
        {
            var config = new AudioConfig();
            var configString = await AgencyAsync.GetModuleConfig(caller, "audio.system");
            config.SetConfig(configString);
            return config;
        }

        public async Task Save(object caller)
        {
            await AgencyAsync.SetModuleConfig(caller, "audio.system", GetConfig());
        }

        public override void SetConfig(String config)
        {
            if (String.IsNullOrEmpty(config)) return;

            var xml = new XmlDocument();
            xml.LoadXml(config);

            var cp = new AttributeParser(xml.DocumentElement);

            RecordDriverID = cp.ParseString("record_driver", null);
            RecordDeviceID = cp.ParseString("record_device", null);
            ReplayDriverID = cp.ParseString("replay_driver", null);
            ReplayDeviceID = cp.ParseString("replay_device", null);
        }

        public override String GetConfig()
        {
            var xml = Xml.Create("root");

            var cw = new AttributeWriter(xml.DocumentElement);

            cw.WriteString("record_driver", RecordDriverID);
            cw.WriteString("record_device", RecordDeviceID);
            cw.WriteString("replay_driver", ReplayDriverID);
            cw.WriteString("replay_device", ReplayDeviceID);

            return xml.InnerXml;
        }

        public override async Task<(ConfigStatus, String)> GetConfigStatus()
        {
            var appMode = await AgencyAsync.GetAppMode();
            if (appMode == ApplicationMode.Online)
            {
                if (RecordDeviceID == null) return (ConfigStatus.Disabled, null);
                else if (!await isRecordDeviceAvailable(RecordDriverID, RecordDeviceID))
                {
                    return (ConfigStatus.EnabledWithError, "Record device unavailable: " + RecordDriverID + ", " + RecordDeviceID);
                }
                else return (ConfigStatus.Enabled, null);
            }
            else if (appMode == ApplicationMode.Offline || appMode == ApplicationMode.Replay)
            {
                if (ReplayDeviceID == null) return (ConfigStatus.Enabled, null);
                else if (!await isReplayDeviceAvailable(ReplayDriverID, ReplayDeviceID))
                {
                    return (ConfigStatus.EnabledWithError, "Replay device unavailable: " + ReplayDriverID + ", " + ReplayDeviceID);
                }
                else return (ConfigStatus.Enabled, null);
            }
            else return (ConfigStatus.Disabled, null);
        }

        public override void DisableAll()
        {
            RecordDriverID = null;
            RecordDeviceID = null;
        }

        public override async Task DisableErrorPart()
        {
            var appMode = await AgencyAsync.GetAppMode();
            if (appMode == ApplicationMode.Online)
            {
                if (RecordDeviceID != null && !await isRecordDeviceAvailable(RecordDriverID, RecordDeviceID))
                {
                    RecordDriverID = null;
                    RecordDeviceID = null;
                }
            }
            else if (appMode == ApplicationMode.Offline || appMode == ApplicationMode.Replay)
            {
                if (ReplayDeviceID != null && !await isReplayDeviceAvailable(ReplayDriverID, ReplayDeviceID))
                {
                    ReplayDriverID = null;
                    ReplayDeviceID = null;
                }
            }
        }

        public String RecordDriverID { get; set; }
        public String RecordDeviceID { get; set; }
        public String ReplayDriverID { get; set; }
        public String ReplayDeviceID { get; set; }

        private async Task<bool> isRecordDeviceAvailable(String recordDriver, String recordDevice)
        {
            var drivers = await AgencyAsync.GetAudioDrivers();
            if (drivers != null && recordDriver != null && recordDevice != null)
            {
                foreach (var d in drivers)
                {
                    if (d.DriverID != recordDriver) continue;
                    var devices = await AgencyAsync.GetAudioRecordDevices(d.DriverID);
                    if (devices != null)
                    {
                        foreach (var device in devices)
                        {
                            if (device.DeviceID != recordDevice) continue;
                            return true;
                        }
                    }
                    break;
                }
            }
            return false;
        }

        private async Task<bool> isReplayDeviceAvailable(String replayDriver, String replayDevice)
        {
            var drivers = await AgencyAsync.GetAudioDrivers();
            if (drivers != null && replayDriver != null && replayDevice != null)
            {
                foreach (var d in drivers)
                {
                    if (d.DriverID != replayDriver) continue;
                    var devices = await AgencyAsync.GetAudioReplayDevices(d.DriverID);
                    if (devices != null)
                    {
                        foreach (var device in devices)
                        {
                            if (device.DeviceID != replayDevice) continue;
                            return true;
                        }
                    }
                    break;
                }
            }
            return false;
        }
    }
}
